Skip to main content

Security Headers

Security headers are HTTP headers that help secure the communication between clients and servers. These headers protect APIs from a range of attacks such as cross-site scripting (XSS), clickjacking, content sniffing, and more.

Common Security Headers

Content-Security-Policy (CSP)

Prevents cross-site scripting (XSS) and code injection by defining which resources are allowed to load.

Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self' api.example.com
  • default-src 'none': block all by default
  • script-src 'self': only allow JS from the API's own domain
  • connect-src: restrict fetch/XHR/websocket destinations APIs that return HTML or are embedded in browsers benefit the most from CSP.

Strict-Transport-Security (HSTS)

Forces HTTPS-only connections to prevent man-in-the-middle (MITM) attacks.

Strict-Transport-Security: max-age=31536000; includeSubDomains
  • max-age: cache HTTPS requirement for 1 year (in seconds)
  • includeSubDomains: enforce for all subdomains Only effective over HTTPS.

X-Content-Type-Options

Prevents MIME-type sniffing by browsers (which can lead to XSS).

X-Content-Type-Options: nosniff

Ensures the browser uses the declared Content-Type, rather than trying to guess it.

Access-Control-Allow-Origin (CORS)

Controls which domains are allowed to access the API via browser.

Access-Control-Allow-Origin: https://frontend.example.com

Crucial for browser-based clients; not typically needed for server-to-server calls.

Cache-Control

Prevent sensitive API responses (like tokens or PII) from being cached.

Cache-Control: no-store
Pragma: no-cache
Expires: 0

Example of Security Header

HTTP/1.1 200 OK
Content-Type: application/json
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'none'; connect-src 'self'
Referrer-Policy: no-referrer
Access-Control-Allow-Origin: https://frontend.example.com
Cache-Control: no-store
Pragma: no-cache

Node.js Implementation

const helmet = require("helmet");
app.use(helmet()); // adds most security headers

// Customize specific headers
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'none'"],
connectSrc: ["'self'", "api.example.com"],
},
})
);

app.get("/api/data", (req, res) => {
res.set("Cache-Control", "no-store");
res.json({ data: "Secure Data" });
});